#!/bin/env python3
# -*- coding: utf-8 -*- (for python2.x)

import sys
import math
import random
import time
import calendar
import datetime
import traceback
import os
import re
import threading    # python3中thread模块已废弃

import psdb

def test_sys_arg(p):
    print('arg number:', len(sys.argv))
    for i, arg in zip(range(0, len(sys.argv)), sys.argv):
        print('%d: %s' % (i, arg))
        i += 1;

def test_format_print(p):
    num = 0x5a
    print('num: hex=%x, dec=%d, oct=%o' % (num, num, num))
    print('pi: d=%d, f=%f, r=%r' % (math.pi, math.pi, math.pi))
    print('pi: 010.3f=%010.3f, .20f=%.20f, -10.3=%-10.3f'
            % (math.pi, math.pi, math.pi))
    print('pi: *.*f=%*.*f' % (10, 3, math.pi))
    print('e: %r' % (math.e))

    c, h, w = '*', 21, 21
    for i in range(h):
        print('%04d:[' % i
                + ' ' * int(w / 2 * (h - i) / h)
                + c * int(w * i / h)
                + ' ' * int(w / 2 * (h - i) / h)
                + ']')
    print('')
    print(sys._getframe().f_code.co_filename)
    print(sys._getframe().f_code.co_name)
    print(sys._getframe().f_lineno)
    print(sys._getframe().f_code)

def test_range(p):
    print('(9):', range(9))
    print('(3, 9):', range(3, 9))
    print('(3, 9, 2):', range(3, 9, 2))
    print('x(9):')
    for i in range(9):
        print('%d,' % i, end='')
    print('')
    print('x(3, 9):',)
    for i in range(3, 9):
        print('%d,' % i, end='')
    print('')
    print('x(3, 9, 2):')
    for i in range(3, 9, 2):
        print('%d,' % i, end='')
    print('')

    s = 'qwertyuiop'
    for i in range(0, len(s)):
        print('[%d]=%s,' % (i, s[i]), end='')
    print('')
    for (i, c) in enumerate(s):
        print('[%d]=%s,' % (i, c), end='')
    print('')

    # 冒泡排序
    a = [ 1, 8, 2, 6, 3, 9, 4, ]
    for i in range(len(a)):
        for j in range(i + 1):
            if a[i] < a[j]:
                a[i], a[j] = a[j], a[i]
    print(a)

    # 2~100之间的素数
    pn = 2
    for pn in range(2, 100):
        i = 2
        while (i <= (pn / i)):
            if not(pn % i):
                break
            i += 1
        else:
            print('%d is prime number' % pn)
    else:
        print('<end>')

def test_math(p):
    i = 123 / 7
    j = 123 // 7
    print('123 / 7 = %d(%%d), %r(%%r)' % (i, i))
    print('123 // 7 = %d(%%d), %r(%%r)' % (j, j))
    a = '0x5a'
    b = '0o12'
    c = '123'
    d = '0b100101'
    print('a: s=%s, hex=%x, dec=%d, oct=%o'
            % (a, int(a, 0), int(a, 0), int(a, 0)))
    print('b: s=%s, hex=%x, dec=%d, oct=%o'
            % (b, int(b, 0), int(b, 0), int(b, 0)))
    print('c: s=%s, hex=%x, dec=%d, oct=%o'
            % (c, int(c, 0), int(c, 0), int(c, 0)))
    print('c: s=%s, hex=%x, dec=%d, oct=%o'
            % (d, int(d, 0), int(d, 0), int(d, 0)))

def test_random(p):
    print('random number(0, 99):')
    r = [ ]
    for i in range(10):
        r.append(random.randint(0, 99))
    print(r)

    print('random choice')
    random.shuffle(r)
    print(r)

    print('sort')
    r.sort()
    print(r)

    print(random.random())
    print(random.uniform(0, 99))

def test_string(p):
    a = 'hello'
    b = 'world'
    print('a:', a)
    print('b:', b)
    print('a + b:', a + b)
    print('a * 3:', a * 3)
    c = 'world, hello'
    print('c:', c)
    print('a in b:', a in b)
    print('b in c:', b in c)
    print('"w" in c:', 'w' in c)
    print('"d, h" in c:', 'd, h' in c)
    print('b == c:', b == c)
    print('b + ', ' + a == c:', b + ', ' + a == c)
    print('[' + a.center(16) + ']')
    print('hello'.center(15).rstrip().title().swapcase())

    i = 12
    d = 'i:%d' % i
    print(d)

def test_calculate_pi(p):
    # 计算圆周率
    n = int(input('Input pi length to calculate:'))
    start_time = time.time()
    w = n + 10
    b = 10 ** w
    x1 = b * 4 // 5
    x2 = b // -239
    s = x1 + x2
    n *= 2
    for i in range(3, n, 2):
        x1 //= -25
        x2 //= -57121
        s += (x1 + x2) // i
    pi = s * 4
    pi //= 10 ** 10
    print('Time consume:', (time.time() - start_time))
    print('Get pi:', pi)

def test_list_tuple_dict(p):
    l1 = ['test1', 'abc', 123, 0]
    print(l1)
    print(l1[-3:])
    print('len: %r' % len(l1))

    l2 = [[]]
    l2[0].append(1)
    l2[0].append(2)
    l2[0].append(3)
    l2[0].append(4)
    l2.append([])
    l2[1].append(5)
    l2[1].append(6)
    l2[1].append(7)
    l2[1].append(8)
    print(l2)

    l3 = [n for n in range(5, 9)]
    print(l3)
    print(type(l3))

    print(['hello' for n in range(3)])

    t1 = (1, 2, 3, 4)
    t2 = ('x', 'p', 'n', 'w')
    t3 = t1 + t2
    print(t3)
    del t2
    print(t3)
    print(type(t3))

    d = {'name' : 'test', 'num' : 123}
    print(d)
    print(type(d))
    print(type(d['name']))
    print(type(d['num']))

def test_time(p):
    print(time.time())
    print(time.localtime())
    print(time.asctime())
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
    print(time.strftime('%a %b %d %H:%M:%S %Y; %Z %x %X', time.localtime()))
    print(time.mktime(time.strptime('Sat Sep 23 14:00:00 2017',
        '%a %b %d %H:%M:%S %Y')))

    print(calendar.month(2017, 1))

    i = datetime.datetime.now()
    print('当前的日期和时间是 %s' % i)
    print('ISO格式的日期和时间是 %s' % i.isoformat() )
    print('当前的年份是 %s' %i.year)
    print('当前的月份是 %s' %i.month)
    print('当前的日期是  %s' %i.day)
    print('dd/mm/yyyy 格式是  %s/%s/%s' % (i.day, i.month, i.year) )
    print('当前小时是 %s' %i.hour)
    print('当前分钟是 %s' %i.minute)
    print('当前秒是  %s' %i.second)

    print('sleep 1s...')
    time.sleep(1)
    print('finish')
    print('sleep 50ms * 20...')
    for i in range(20):
        print('.', end='')
        sys.stdout.flush()
        time.sleep(0.05)
    print('finish')

def test_help(p):
    help(sys)
    help(str)
    print(dir(sys))
    print(dir(str))

def test_function(p):
    def func_test1():
        print('%s:%d' % (sys._getframe().f_code.co_filename,
            sys._getframe().f_lineno))
    print(func_test1())

    def func_test2(num1, num2):
        return num1 + num2
    print(func_test2(2, 3))

    # 输出调用关系
    def get_caller():
        str = '%s > ' % __name__
        for i in range(5):
            if sys._getframe(i).f_back == None:
                break
        else:
            str += '... '
        for i in range(i, 0, -1):
            str += '%s:%d ' % (sys._getframe(i).f_code.co_name,
                    sys._getframe(i).f_lineno)
        return str
    def get_cur_info():
        print(get_caller())
    def get_cur_info_2():
        get_cur_info()
    def get_cur_info_3():
        get_cur_info_2()
    def get_cur_info_4():
        print(get_caller())
        get_cur_info_3()
    def func_test3():
        get_cur_info_4()
    print(get_caller())
    print(func_test3())

    # 匿名函数
    get_sum = lambda a1, a2: a1 + a2
    print(get_sum(12, 13))

    # 函数不定参数
    def get_sum_mix(*argv):
        s = 0
        for arg in argv:
            s += arg
        return s
    print('Get sum: %d' % (get_sum_mix(1, 2, 3, 4)))

    print('Locals: %r' % locals())
    print('Globals: %r' % globals())

def test_input(p):
    #  str = raw_input('input some thing:')
    #  print(str)

    print('input some thing or expression:')
    print('(e.g.: [x * 5 for x in  range(10)])')
    str = input()
    print(str)

def test_try(p):
    print('try...')
    try:
        r = int(input('input a number:'))
        print('get r = %r' % r)
    except Exception as e:
        print('get exception: %r' % e)
        traceback.print_exc()
    except:
        print('unknown exception!')
    else:               # 无异常时执行
        print('success')
    finally:            # 退出try时执行
        print('<end>')

    print('continue')

    def raise_exception():
        try:
            raise print('!!! my error')   # throw an exception
            print('process')
        except:
            print('raise error')
            raise       # 将拦截到的异常错误抛出给上层处理

    def process_exception():
        try:
            raise_exception()
        except:
            print('get an exception, throw')
            raise           # 将拦截到的异常错误抛出给上层处理

    try:
        print('run function')
        process_exception()
    except Exception as e:
        print('get an exception: %r' % e)
        traceback.print_exc()
    else:
        print('exception not found!')
    finally:
        print('<end>')

def test_file(p):
    fn = './test_file'
    print('open file: %s(rb+)' % fn)
    try:
        f = open(fn, 'rb+')
    except Exception as e:
        print('open failed: %s' % e)
        print('retry open(wb+)')
        try:
            f = open(fn, 'wb+')
            print('file object: %s' % f)
        except Exception as e:
            print('retry failed: %s' % e)
            return
    print('write file')
    f.write('This is a test file!'.encode())
    f.write(b'The second line.')
    f.write(b'<\x01\x02\x00\x04>abc')
    print('close file')
    f.close()

    print('open file: %s(r+)' % fn)
    f = open(fn, 'rb+')
    buf = f.read()
    print('file content: %s' % buf.decode())
    print('file content: %s' % buf)
    print('close file')
    f.close()

    print('file access:')
    if os.access(fn, os.F_OK):
        print('\t file exist')
    if os.access(fn, os.R_OK):
        print('\t file is accessible to read')
    if os.access(fn, os.W_OK):
        print('\t file is accessible to write')
    if os.access(fn, os.X_OK):
        print('\t file is accessible to execute')

    if os.path.exists(fn):
        print('file(%s) exist, remove' % fn)
        os.remove(fn)
    else:
        print('file(%s) not found' % fn)
    print('Current path:%s' % os.getcwd())
    for fn in os.listdir():
        print('   + %s' % fn)

def test_class(p):
    class Test:
        '测试类'                            # __doc__
        __test_count = 0                    # 类变量, 所有实例共享
                                            # 2个下划线开头: private
        def __init__(self, name='none'):    # 构造函数, 创建实例时调用
            self._name = name               # 1个下划线开头: protected
            self.__test_count += 1
            print('创建Test实例:%s' % name)

        def __del__(self):
            self.__test_count -= 1
            print('销毁Test实例:%s' % self._name)

        def disp_count(self):
            print('Test.count: %d' % self.__test_count)

        def disp_test(self):
            print('name: %s' % self._name)

    print(' * class attribute: %r' % Test.__dict__)
    print(' * class doc: %r' % Test.__doc__)
    print(' * class name: %r' % Test.__name__)
    print(' * class module: %r' % Test.__module__)
    print(' * class bases: %r' % Test.__bases__)

    t1 = Test('t1')
    t1.disp_count()
    t1.disp_test()
    t2 = Test('t2')
    t2.disp_count()
    t2.disp_test()
    del t1
    del t2

    print('')

    class TestChild(Test):
        def __init__(self, name='none'):
            super().__init__(name)  # 推荐写法, 同Test.xxx(self, ...),
                                    #   不受父类改名影响
                                    #   python2中应该写为:super(Test, self).xxx

        def __del__(self):
            super().__del__()

        def disp_test(self):        # 重写方法
            print('child name: %s' % self._name)

    tc1 = TestChild('tc1')
    tc1.disp_test()
    del tc1

    class TestB:
        def disp_count(self):
            print('TestB has nothing to count')
    class TestChildB(TestB):
        pass
        #  def disp_count(self):
        #      print('TestChildB has nothing to count')

    # 继承顺序影响同名方法查找顺序
    class TestChildChild(TestChildB, TestChild):
        pass

    tcc1 = TestChildChild('tcc1')
    tcc1.disp_test()
    tcc1.disp_count()
    del tcc1
    print('check TestChildChild MRO: %r' % TestChildChild.mro())

    print('')

    class Vector:
        def __init__(self, a, b):
            self.a = a
            self.b = b

        def __str__(self):
            return 'Vector (%d, %d)' % (self.a, self.b)

        def __add__(self,other):
            return Vector(self.a + other.a, self.b + other.b)

    v1 = Vector(2, 10)
    v2 = Vector(5, -2)
    print(v1 + v2)

    print('<end>')

def test_re(p):
    string = 'www.test.com aaa bb c 123 www.zzz.com xxx yy z'
    print(re.match('www', string))
    print(re.match('test', string))

    m = re.match('www.(.*).com', string)
    print(m.group(0))
    print(m.group(1))

    print(re.search('www', string))
    print(re.search('test', string))

    m = re.search('www.(.*).com', string)
    print(m.group(0))
    print(m.group(1))

    print('<end>')

def test_thread(p):
    print('')

    def print_time(name='none', delay=1):
        print('[%s start]' % name)
        count = 0
        while count < 10:
            time.sleep(delay)
            count += 1
            print(' > %s: %s' % (name, time.ctime(time.time())))
        print('[%s exit]' % name)

    t1 = threading.Thread(target = print_time, args = ('t1', 0.5),
            name = 'thead-1')
    print('%s ready to start' % (t1.getName()))
    t1.start()
    t2 = threading.Thread(target = print_time, args = ('t2', 0.2),
            name = 'thread-2')
    print('%s ready to start' % (t2.getName()))
    t2.start()
    print('waiting threads finish...')
    t1.join()
    t2.join()
    print('OK\n')

    print('continue')
    class Timer(threading.Thread):
        def __init__(self, name=None, delay=None):
            super().__init__()
            self.name = name
            self.delay = delay

        def run(self):
            print('Thread:%s, delay:%rms' % (self.name, self.delay))
            print_time(self.name, self.delay)

    t1 = Timer('t1', 0.542)
    t1.start()
    t2 = Timer('t2', 0.285)
    t2.start()
    while 1:
        if not t1.is_alive() and not t2.is_alive():
            break
        print('waiting threads finish(%#x:%r, %#x:%r)'
                % (t1.ident, t1.is_alive(), t2.ident, t2.is_alive()))
        time.sleep(0.5)

    print('continue')
    class Timer_lock(threading.Thread):
        __lock = threading.Lock()

        def __init__(self, name=None, delay=None):
            super().__init__()
            self.name = name
            self.delay = delay

        def run(self):
            self.__lock.acquire()
            print('Thread:%s, delay:%rms' % (self.name, self.delay))
            print_time(self.name, self.delay)
            self.__lock.release()

    t1 = Timer_lock('t1', 0.5)
    t1.start()
    t2 = Timer_lock('t2', 0.2)
    t2.start()
    print('waiting threads finish...')
    t1.join()
    t2.join()

    print('<end>')

def test_with(p):
    # with语句仅用于支持上下文管理协议的对象:
    #   file
    #   decimal.Context
    #   thread.LockType
    #   threading.Lock
    #   threading.RLock
    #   threading.Condition
    #   threading.Semaphore
    #   threading.BoundedSemaphore

    # 自定义类使用with上下文管理
    class auto_exit:
        def __enter__(self):
            print('auto_exit enter')
            return self

        def run(self):
            print('auto_exit run')
            #  raise

        def __exit__(self, e_t, e_v, t_b):
            print('auto_exit exit')
            print('e_t:%r' % e_t)
            print('e_v:%r' % e_v)
            print('t_b:%r' % t_b)

    with auto_exit() as a:  # __exit__总是会被执行, 无论是否出现异常
        a.run()
        print('finish')
        #  raise

    print('<end>')

def main():
    print('Module: %r' % (__name__))
    print('python syntax tests; ')
    print('python语法测试;')
    print('python version: %s' % (sys.version))

    menu = [
            { 'name' : 'sys.arg', 'param' : 0, 'func' : test_sys_arg, },
            { 'name' : 'format print', 'param' : 0, 'func' : test_format_print, },
            { 'name' : 'range', 'param' : 0, 'func' : test_range, },
            { 'name' : 'math', 'param' : 0, 'func' : test_math, },
            { 'name' : 'random', 'param' : 0, 'func' : test_random, },
            { 'name' : 'string', 'param' : 0, 'func' : test_string, },
            { 'name' : 'calculate pi', 'param' : 0, 'func' : test_calculate_pi, },
            { 'name' : 'list & tuple & dict', 'param' : 0, 'func' : test_list_tuple_dict, },
            { 'name' : 'time', 'param' : 0, 'func' : test_time, },
            { 'name' : 'help', 'param' : 0, 'func' : test_help, },
            { 'name' : 'function', 'param' : 0, 'func' : test_function, },
            { 'name' : 'input', 'param' : 0, 'func' : test_input, },
            { 'name' : 'try', 'param' : 0, 'func' : test_try, },
            { 'name' : 'file', 'param' : 0, 'func' : test_file, },
            { 'name' : 'class', 'param' : 0, 'func' : test_class, },
            { 'name' : 're', 'param' : 0, 'func' : test_re, },
            { 'name' : 'thread', 'param' : 0, 'func' : test_thread, },
            { 'name' : 'with', 'param' : 0, 'func' : test_with, },
            ]
    psdb.sdb_menu(menu)

if __name__ == '__main__':
    main()
else:
    pass


